package com.xinzhidi.web.alarmSetting.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.xinzhidi.common.constant.AgreementConstants;
import com.xinzhidi.common.core.domain.model.LoginUser;
import com.xinzhidi.common.core.page.TableDataInfo;
import com.xinzhidi.common.exception.ServiceException;
import com.xinzhidi.common.utils.DateUtils;
import com.xinzhidi.common.utils.SecurityUtils;
import com.xinzhidi.common.utils.StringUtils;
import com.xinzhidi.common.utils.bean.BeanUtils;
import com.xinzhidi.system.service.ISysDictDataService;
import com.xinzhidi.system.service.ISysUserService;
import com.xinzhidi.web.alarmSetting.domain.AlarmSetting;
import com.xinzhidi.web.alarmSetting.domain.dto.AlarmSettingAddDto;
import com.xinzhidi.web.alarmSetting.domain.dto.AlarmSettingListDto;
import com.xinzhidi.web.alarmSetting.domain.dto.AlarmSettingUpdDto;
import com.xinzhidi.web.alarmSetting.domain.dto.AlarmSettingVoDto;
import com.xinzhidi.web.alarmSetting.domain.vo.AlarmSettingInfoVo;
import com.xinzhidi.web.alarmSetting.domain.vo.AlarmSettingListVo;
import com.xinzhidi.web.alarmSetting.mapper.AlarmSettingMapper;
import com.xinzhidi.web.build.service.IBuildUnitService;
import com.xinzhidi.web.equipment.domain.Equipment;
import com.xinzhidi.web.equipmentAlarm.domain.EquipmentAlarm;
import com.xinzhidi.web.equipmentAlarm.domain.dto.EquipmentAlarmDto;
import com.xinzhidi.web.equipmentAlarm.service.EquipmentAlarmService;
import com.xinzhidi.web.house.service.IHouseholdService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;


/**
 * 告警设置Service业务层处理
 *
 * @author ruoyi
 * @date 2023-05-31
 */
@Service
public class AlarmSettingService extends ServiceImpl<AlarmSettingMapper, AlarmSetting> {
    @Autowired
    private AlarmSettingMapper alarmSettingMapper;
    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private EquipmentAlarmService equipmentAlarmService;

    @Autowired
    private IHouseholdService householdService;

    @Autowired
    private IBuildUnitService buildUnitService;

    @Autowired
    private ISysDictDataService sysDictDataService;

    /**
     * 查询告警设置
     *
     * @param id 告警设置主键
     * @return 告警设置
     */
    public AlarmSettingInfoVo selectAlarmSettingById(Long id) {
        AlarmSetting alarmSetting = alarmSettingMapper.selectById(id);
        AlarmSettingInfoVo infoVo = new AlarmSettingInfoVo();
        BeanUtils.copyProperties(alarmSetting, infoVo);
        return infoVo;
    }

    /**
     * 查询告警设置列表
     *
     * @param dto 查询告警设置dto
     * @return 告警设置
     */
    public TableDataInfo<AlarmSettingListVo> selectAlarmSettingList(AlarmSettingListDto dto) {
        List<AlarmSettingListVo> list = alarmSettingMapper.getSettingList(dto);
        if (CollectionUtils.isNotEmpty(list)) {
            return TableDataInfo.getDataTable(list);
        }
        return TableDataInfo.getDataTable(list, (domain -> {
            return null;
        }));
    }

    /**
     * 新增告警设置
     *
     * @param dto 新增告警设置dto
     * @return 结果
     */
    public int insertAlarmSetting(AlarmSettingAddDto dto) {
        AlarmSettingUpdDto updDto = new AlarmSettingUpdDto();
        BeanUtils.copyProperties(dto, updDto);

        this.checkExist(updDto);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        AlarmSetting alarmSetting = new AlarmSetting();
        BeanUtils.copyProperties(dto, alarmSetting);
        String dictLabel = sysDictDataService.selectDictLabel("alarm_type", dto.getAlarmType());
        alarmSetting.setAlarmTypeName(dictLabel);
        alarmSetting.setCreateBy(loginUser.getUserId().toString());
        alarmSetting.setCreateTime(DateUtils.getNowDate());
        return alarmSettingMapper.insert(alarmSetting);
    }

    /**
     * 修改告警设置
     *
     * @param dto 修改告警设置dto
     * @return 结果
     */
    public int updateAlarmSetting(AlarmSettingUpdDto dto) {
        this.checkExist(dto);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        AlarmSetting alarmSetting = new AlarmSetting();
        BeanUtils.copyProperties(dto, alarmSetting);
        alarmSetting.setUpdateBy(loginUser.getUserId().toString());
        alarmSetting.setUpdateTime(DateUtils.getNowDate());
        return alarmSettingMapper.updateById(alarmSetting);
    }

    public void checkExist(AlarmSettingUpdDto dto) {
        LambdaQueryWrapper<AlarmSetting> settingWrapper = Wrappers.lambdaQuery();
        settingWrapper.ne(dto.getId() != null, AlarmSetting::getId, dto.getId())
                .eq(StringUtils.isNotBlank(dto.getAlarmType()), AlarmSetting::getAlarmType, dto.getAlarmType())
                .eq(StringUtils.isNotBlank(dto.getEquipmentType()), AlarmSetting::getEquipmentType, dto.getEquipmentType())
                .eq(StringUtils.isNotBlank(dto.getIndexType()), AlarmSetting::getIndexType, dto.getIndexType());

        if (alarmSettingMapper.selectCount(settingWrapper) > 0) {
            throw new ServiceException("该告警设置已存在！");
        }
    }


    /**
     * 批量删除告警设置
     *
     * @param ids 需要删除的告警设置主键
     * @return 结果
     */
    public boolean deleteAlarmSettingByIds(Long[] ids) {
        UpdateWrapper<AlarmSetting> wrapper = new UpdateWrapper<>();
        wrapper.set("del_flag", "1").in("id", ids);
        return this.update(wrapper);
    }

    /**
     * 删除告警设置信息
     *
     * @param id 告警设置主键
     * @return 结果
     */
    public int deleteAlarmSettingById(Long id) {
        return alarmSettingMapper.deleteById(id);
    }

    public List<AlarmSetting> listAlarmSettingSelect(AlarmSettingListDto dto) {
        LambdaQueryWrapper<AlarmSetting> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(StringUtils.isNotEmpty(dto.getAlarmType()), AlarmSetting::getAlarmType, dto.getAlarmType());
        wrapper.like(StringUtils.isNotEmpty(dto.getIndexType()), AlarmSetting::getIndexType, dto.getIndexType());
        wrapper.eq(StringUtils.isNotEmpty(dto.getAlarmLevel()), AlarmSetting::getAlarmLevel, dto.getAlarmLevel());
        wrapper.eq(StringUtils.isNotEmpty(dto.getPushStatus()), AlarmSetting::getPushStatus, dto.getPushStatus());
        wrapper.orderByDesc(AlarmSetting::getId);
        List<AlarmSetting> list = alarmSettingMapper.selectList(wrapper);
        return list;
    }

    /**
     * 修改推送状态
     *
     * @param id 查询告警设置id
     */
    public int editPushStatus(Long id, String pushStatus) {
        AlarmSetting alarmSetting = alarmSettingMapper.selectById(id);
        if (alarmSetting == null) {
            throw new ServiceException("告警设置不存在");
        }
        alarmSetting.setPushStatus(pushStatus);
        return alarmSettingMapper.updateById(alarmSetting);
    }

    /**
     * 获取单条告警设置
     *
     * @return
     */
    public AlarmSettingListVo getAlarmSettingVo(AlarmSettingVoDto dto) {
        AlarmSettingListVo vo = new AlarmSettingListVo();
        AlarmSettingListDto listDto = new AlarmSettingListDto();
        BeanUtils.copyProperties(dto, listDto);
        List<AlarmSettingListVo> list = alarmSettingMapper.getSettingList(listDto);
        if (CollectionUtils.isNotEmpty(list)) {
            if (list.size() > 0) {
                throw new ServiceException("系统错误，查询出条告警设置！");
            }
            vo = list.get(0);
        }
        return vo;
    }

    /**
     * 检查获取到的设备上报数据是否超限异常
     *
     * @return
     */
    public void fieldCheck(Equipment equipment, Map<String, Object> map) {
        String protocolType = equipment.getProtocolType();
        //如果是户用热量表或单元热量表，才需要做超限检查
        if (!protocolType.equals(AgreementConstants.AgreementType.HOUSEHOLD_HEAT_METER) && !protocolType.equals(AgreementConstants.AgreementType.UNIT_HEAT_METER)) {
            return;
        }
        AlarmSettingListDto dto = new AlarmSettingListDto();
        dto.setAlarmType(AgreementConstants.ExceptionType.TRANSFINITE_EXCEPTION);
        List<AlarmSetting> list = this.listAlarmSettingSelect(dto);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        EquipmentAlarm equipmentAlarm;
        List<EquipmentAlarm> alarmList = Lists.newArrayList();
        EquipmentAlarmDto alarmDto;
        BigDecimal minValue;
        BigDecimal maxValue;
        BigDecimal value;
        //开始---------------------
        String checkField;
        for (AlarmSetting setting : list) {
            checkField = setting.getCheckField();
            if (!map.containsKey(checkField)) {
                continue;
            }
            String indexTypeName;
            minValue = setting.getMinValue();
            maxValue = setting.getMaxValue();
            value = (BigDecimal) map.get(checkField);
            if (value.compareTo(minValue) < 0
                    || value.compareTo(maxValue) > 0) {
                //判断异常信息是否已存在，存在则修改为已处理，不存在则新增
                alarmDto = new EquipmentAlarmDto();
                alarmDto.setEquipmentId(equipment.getId());
                alarmDto.setAlarmSettingId(setting.getId());
                alarmDto.setStatus("0");
                alarmDto.setRemark("超限异常");
                equipmentAlarm = equipmentAlarmService.getByParam(alarmDto);
                if (equipmentAlarm == null) {
                    equipmentAlarm = new EquipmentAlarm();
                    equipmentAlarm.setPlotId(equipment.getLotId());
                    equipmentAlarm.setBuildId(equipment.getBuildId());
                    equipmentAlarm.setUnitId(equipment.getUnitId());
                    equipmentAlarm.setHouseholdId(equipment.getHouseholdId());
                    equipmentAlarm.setEquipmentId(equipment.getId());
                    equipmentAlarm.setAlarmSettingId(setting.getId());
                    equipmentAlarm.setHideOrPush(Integer.parseInt(setting.getPushStatus()));
                    equipmentAlarm.setPushNum(setting.getPushInterval());
                }
                indexTypeName = sysDictDataService.selectDictLabel("control_tactics", setting.getIndexType());
                equipmentAlarm.setRemark("设备【" + equipment.getAddress() + "】" + indexTypeName + "超限异常。范围：" + minValue + "~" + maxValue + "，当前值：" + value + "");
                alarmList.add(equipmentAlarm);
            }
        }

        //结束---------------------
        if (CollectionUtils.isNotEmpty(alarmList)) {
            equipmentAlarmService.saveOrUpdateBatch(alarmList);
        }
    }

    public void fluctuationException(Equipment equipment, Map<String, Object> map) {
        String protocolType = equipment.getProtocolType();
        //如果是户用热量表或单元热量表，才需要做波动异常检查
        if (!protocolType.equals(AgreementConstants.AgreementType.HOUSEHOLD_HEAT_METER) && !protocolType.equals(AgreementConstants.AgreementType.UNIT_HEAT_METER)) {
            return;
        }
        AlarmSettingListDto dto = new AlarmSettingListDto();
        dto.setAlarmType(AgreementConstants.ExceptionType.UNDULATE_EXCEPTION);
        List<AlarmSetting> list = this.listAlarmSettingSelect(dto);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        //开始--------------------
        String checkField;
        //波动值
        BigDecimal fluctuatingValue;
        List<EquipmentAlarm> alarmList = Lists.newArrayList();
        EquipmentAlarm equipmentAlarm;
        EquipmentAlarmDto alarmDto;
        BigDecimal value;
        BigDecimal maxValue;
        BigDecimal minValue;
        for (AlarmSetting setting : list) {
            checkField = setting.getCheckField();
            if (!map.containsKey(checkField)) {
                continue;
            }
            fluctuatingValue = setting.getFluctuatingValue();
            //判断是否是波动异常
            //1：获取上次的数值
            value = this.getLastValue(equipment, setting);
            //2：判断是否在波动异常范围内
            if (value == null) {
                continue;
            }
            maxValue = value.add(fluctuatingValue);
            minValue = value.subtract(fluctuatingValue);
            //如果不在范围内，则进行下一个循环
            if (value.compareTo(minValue) > 0 && value.compareTo(maxValue) < 0) {
                continue;
            }
            //判断异常信息是否已存在，存在则修改为已处理，不存在则新增
            alarmDto = new EquipmentAlarmDto();
            alarmDto.setEquipmentId(equipment.getId());
            alarmDto.setAlarmSettingId(setting.getId());
            alarmDto.setStatus("0");
            alarmDto.setRemark("波动异常");
            equipmentAlarm = equipmentAlarmService.getByParam(alarmDto);
            if (equipmentAlarm == null) {
                equipmentAlarm = new EquipmentAlarm();
                equipmentAlarm.setPlotId(equipment.getLotId());
                equipmentAlarm.setBuildId(equipment.getBuildId());
                equipmentAlarm.setUnitId(equipment.getUnitId());
                equipmentAlarm.setHouseholdId(equipment.getHouseholdId());
                equipmentAlarm.setEquipmentId(equipment.getId());
                equipmentAlarm.setAlarmSettingId(setting.getId());
                equipmentAlarm.setHideOrPush(Integer.parseInt(setting.getPushStatus()));
                equipmentAlarm.setPushNum(setting.getPushInterval());

            }
            equipmentAlarm.setRemark("设备【" + equipment.getAddress() + "】" + setting.getIndexTypeName() + "波动异常。上次数值：" + minValue + "波动范围" + fluctuatingValue + "，当前值：" + value + "");
            alarmList.add(equipmentAlarm);
        }
        //结束--------------------
        if (CollectionUtils.isNotEmpty(alarmList)) {
            equipmentAlarmService.saveOrUpdateBatch(alarmList);
        }
    }

    /**
     * 获取上次的数值
     *
     * @param equipment 设备
     * @param setting   告警设置
     * @return
     */
    private BigDecimal getLastValue(Equipment equipment, AlarmSetting setting) {
        String checkField = setting.getCheckField();
        checkField = "\'$." + checkField + "\'";
        String equipmentLevel = setting.getEquipmentType();
        BigDecimal value = this.baseMapper.getLastValue(equipment.getDtuId(), equipment.getAddress(), checkField);
        //获取上次的数值
        return value;
    }

}
